package org.rainbowinverted.charging.device.connect.ykc.server.handler;

import cn.hutool.core.codec.BCD;
import org.rainbowinverted.charging.device.api.operation.dto.resp.DeviceRespOnlineDTO;
import org.rainbowinverted.charging.device.connect.ykc.server.attribute.DeviceInfo;
import org.rainbowinverted.charging.device.connect.ykc.server.constants.ChannelAttributeKeyConstants;
import org.rainbowinverted.charging.device.connect.ykc.server.constants.YkcDeviceNetworkTypeConstants;
import org.rainbowinverted.charging.device.connect.ykc.server.constants.YkcDeviceOperatorTypeConstants;
import org.rainbowinverted.charging.device.connect.ykc.server.message.in.YkcDeviceLoginIn;
import org.rainbowinverted.charging.device.connect.ykc.server.message.in.YkcMessageIn;
import org.rainbowinverted.charging.device.connect.ykc.server.message.out.YkcDeviceLoginOut;
import org.rainbowinverted.charging.device.connect.ykc.server.message.out.YkcDeviceQrcodeOut;
import org.rainbowinverted.charging.device.connect.ykc.server.message.out.YkcDeviceTimeSyncOut;
import org.rainbowinverted.charging.device.connect.ykc.server.util.SerialNumberGenerator;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;

/**
 * 云快充登录处理器
 * @author hehuaiping
 */
@Slf4j
@Component
@ChannelHandler.Sharable
@AllArgsConstructor
public class YkcDeviceLoginHandler extends YkcAbstractHandler<YkcDeviceLoginIn, YkcDeviceLoginOut>{
    // private final DeviceEventComponent deviceEventComponent;
    private final static Integer DEFAULT_GSM = 20;

    @Override
    public void read(ChannelHandlerContext channel, YkcMessageIn message) {
        ByteBuf messageBody = message.getMessageBody();
        // 设备编号
        Long deviceNo = readDeviceNo(messageBody);
        // 桩类型，0 表示直流桩，1 表示交流桩
        Boolean acOrDirectType = messageBody.readByte() == 0x01;
        // 充电枪数量
        Integer gunCount = readByteToInt(messageBody);
        // 通信协议版本, 版本号乘 10，v1.0 表示 0x0A
        String protocolVersion = String.format("v%.1f", (double)readByteToInt(messageBody) / 10);
        // 程序版本
        byte[]  programVersionBytes = new byte[8];
        messageBody.readBytes(programVersionBytes);
        String programVersion = new String(programVersionBytes, StandardCharsets.UTF_8);
        // 网络链接类型
        byte networkTypeByte = messageBody.readByte();
        // sim卡
        byte[] simBytes = new byte[10];
        messageBody.readBytes(simBytes);
        String simCardNo = BCD.bcdToStr(simBytes);
        // 运营商
        byte operatorByte = messageBody.readByte();
        YkcDeviceLoginIn ykcDeviceLoginIn = YkcDeviceLoginIn.of(deviceNo, acOrDirectType, gunCount, protocolVersion,
                programVersion, parseNetworkType(networkTypeByte), simCardNo, parseOperatorType(operatorByte));
        log.info("device login: {}", ykcDeviceLoginIn);
        // 广播设备上线
/*        deviceEventComponent.broadcastDeviceOnlineReport(DeviceRespOnlineDTO.of(deviceNo, programVersion,
                DEFAULT_GSM, simCardNo, LocalDateTime.now()));*/
        // 将channel添加到map中
        channel.channel().attr(ChannelAttributeKeyConstants.CHANNEL_ATTR_DEVICE_NO).set(deviceNo);
        // 保存设备设备信息
        channel.channel().attr(ChannelAttributeKeyConstants.CHANNEL_ATTR_DEVICE_INFO).set(
                DeviceInfo.of(deviceNo, simCardNo, false));
        putChannel(deviceNo, channel);
        // 回复登录结果
        channel.writeAndFlush(new YkcDeviceLoginOut(message.getFrameSerialNo(), deviceNo, Boolean.TRUE));
        // 发送校时命令
        channel.writeAndFlush(new YkcDeviceTimeSyncOut(SerialNumberGenerator.nextSerialNumber(), deviceNo, LocalDateTime.now()));
        // 更新二维码
        channel.writeAndFlush(YkcDeviceQrcodeOut.of(SerialNumberGenerator.nextSerialNumber(), deviceNo));
    }

    private String parseNetworkType(byte networkByteType) {
        return switch (networkByteType) {
            case 0x00 -> YkcDeviceNetworkTypeConstants.SIM_CARD;
            case 0x01 -> YkcDeviceNetworkTypeConstants.LAN;
            case 0x02 -> YkcDeviceNetworkTypeConstants.WAN;
            default -> YkcDeviceNetworkTypeConstants.OTHER;
        };
    }
    private String parseOperatorType(byte operatorByte) {
        return switch (operatorByte) {
            case 0x00 -> YkcDeviceOperatorTypeConstants.CMCC;
            case 0x02 -> YkcDeviceOperatorTypeConstants.CTCC;
            case 0x03 -> YkcDeviceOperatorTypeConstants.CUCC;
            default -> YkcDeviceOperatorTypeConstants.OTHER;
        };
    }

    @Override
    public void write(ByteBuf byteBuf, YkcDeviceLoginOut out) {
        writeDeviceNo(byteBuf, out.getDeviceNo());
        byteBuf.writeByte(out.getLoginResult() ? 0x00 : 0x01);
    }
}
